﻿// Decompiled with JetBrains decompiler
// Type: DnProcessSimulateCommands.SweptVolume.CApSVOrderedLocationsSimulationHandler
// Assembly: DnProcessSimulateCommands, Version=2402.0.0.890, Culture=neutral, PublicKeyToken=null
// MVID: A885D881-AEDF-447E-852A-6F13102E089C
// Assembly location: C:\Program Files\Tecnomatix_2402\eMPower\DotNetCommands\DnProcessSimulateCommands.dll

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Tecnomatix.Engineering;
using Tecnomatix.Engineering.Olp;
using Tecnomatix.Engineering.Olp.PrivateImplementationDetails;


namespace DnProcessSimulateCommands.SweptVolume;

public class CApSVOrderedLocationsSimulationHandler : CApSimulationHandler
{
  private ITxLocationOperation m_from;
  private ITxLocationOperation m_to;
  private ITxLocationOperation m_lastLocationReached;
  private TxObjectList m_operationLocations;
  private double m_timeAtLastLocationReached;
  private bool m_lastLocationSampled;
  private bool _firstLocationSampled;
  private bool m_reachedAllLocations;
  private const double _EPSILON = 0.001;
  private bool m_isHandledFirstLocationReached;
  private bool m_isRegisteredToOperationReachedEvent;
  private bool m_isRegisteredToRoboticOlpEvents;

  public CApSVOrderedLocationsSimulationHandler(ITxOrderedCompoundOperation operation)
    : base((ITxOperation) operation)
  {
    this.m_operationLocations = new TxObjectList();
    this.appendOperationLocations((ITxOperation) operation);
    this.m_from = this.FirstLocation;
    this.m_to = this.LastLocation;
    this.m_lastLocationReached = (ITxLocationOperation) null;
    this.m_timeAtLastLocationReached = 0.0;
    this.m_lastLocationSampled = false;
    this._firstLocationSampled = false;
    this.m_reachedAllLocations = false;
  }

  public CApSVOrderedLocationsSimulationHandler(ITxRoboticProgram roboticProgram)
    : base(roboticProgram)
  {
    this.m_operationLocations = new TxObjectList();
    TxTypeFilter txTypeFilter = new TxTypeFilter(typeof (ITxOperation));
    foreach (ITxOperation directChildElement in (Collection<ITxObject>) roboticProgram.GetDirectChildElements((ITxTypeFilter) txTypeFilter))
      this.appendOperationLocations(directChildElement);
    this.m_from = this.FirstLocation;
    this.m_to = this.LastLocation;
    this.m_lastLocationReached = (ITxLocationOperation) null;
    this.m_timeAtLastLocationReached = 0.0;
    this.m_lastLocationSampled = false;
    this._firstLocationSampled = false;
    this.m_reachedAllLocations = false;
  }

  public ITxLocationOperation LastLocationReached => this.m_lastLocationReached;

  public double TimeAtLastLocationReached => this.m_timeAtLastLocationReached;

  public ITxLocationOperation FirstLocation
  {
    get => ((Collection<ITxObject>) this.m_operationLocations)[0] as ITxLocationOperation;
  }

  public ITxLocationOperation LastLocation
  {
    get
    {
      return ((Collection<ITxObject>) this.m_operationLocations)[((Collection<ITxObject>) this.m_operationLocations).Count - 1] as ITxLocationOperation;
    }
  }

  public bool ReachedAllLocations => this.m_reachedAllLocations;

  public override void init()
  {
    base.init();
    this.m_isHandledFirstLocationReached = false;
    this.m_simulationPlayer.OperationEndedForward += new TxSimulationPlayer_OperationEndedForwardEventHandler(this.onOperationEndedForward);
    if (this.m_from != null && this.m_from is ITxRoboticLocationOperation)
    {
      this.RegisterToRoboticOlpEvents();
    }
    else
    {
      if (this.m_isRegisteredToOperationReachedEvent)
        return;
      this.m_simulationPlayer.OperationReachedDestination += new TxSimulationPlayer_OperationReachedDestinationEventHandler(this.m_simulationPlayer_OperationReachedDestination);
      this.m_isRegisteredToOperationReachedEvent = true;
    }
  }

  public override bool maySample()
  {
    bool flag1 = false;
    if (this.m_lastLocationReached != null)
    {
      int num = ((Collection<ITxObject>) this.m_operationLocations).IndexOf((ITxObject) this.m_lastLocationReached);
      if (num >= 0)
      {
        bool flag2 = num >= ((Collection<ITxObject>) this.m_operationLocations).IndexOf((ITxObject) this.m_from);
        bool flag3 = num < ((Collection<ITxObject>) this.m_operationLocations).IndexOf((ITxObject) this.m_to);
        if (!flag3 && !this.m_lastLocationSampled)
        {
          flag3 = true;
          this.m_lastLocationSampled = true;
        }
        flag1 = flag2 & flag3;
      }
      else if (this.m_isHandledFirstLocationReached && !this.m_lastLocationSampled && this.m_lastLocationReached is ITxRoboticLocationOperation && this.m_from is ITxRoboticLocationOperation)
      {
        ITxRoboticOrderedCompoundOperation roboticOperation1 = (this.m_lastLocationReached as ITxRoboticLocationOperation).ParentRoboticOperation;
        ITxRoboticOrderedCompoundOperation roboticOperation2 = (this.m_from as ITxRoboticLocationOperation).ParentRoboticOperation;
        if (roboticOperation1 != null && roboticOperation2 != null && roboticOperation1.Robot == roboticOperation2.Robot)
          flag1 = true;
      }
    }
    if (!this._firstLocationSampled)
    {
      this._firstLocationSampled = true;
      if (this.m_simulatingObject is TxObjectFlowOperation)
      {
        ITxLocatableObject itxLocatableObject;
        try
        {
          itxLocatableObject = (this.m_simulatingObject as TxObjectFlowOperation).SimulatedObject;
        }
        catch (TxPartHasNoAppearanceException ex)
        {
          itxLocatableObject = (ITxLocatableObject) null;
        }
        if (itxLocatableObject != null && ((Collection<ITxObject>) this.m_operationLocations).Count > 0 && ((Collection<ITxObject>) this.m_operationLocations)[0] is TxObjectFlowLocationOperation)
        {
          TxBoundingBoxCalculator boundingBoxCalculator = new TxBoundingBoxCalculator();
          boundingBoxCalculator.AddObject((ITxObject) (this.m_simulatingObject as TxObjectFlowOperation).SimulatedObject);
          flag1 = this.AreTxTransformationsEqual(boundingBoxCalculator.CalculateGeometricCenter(), (((Collection<ITxObject>) this.m_operationLocations)[0] as TxObjectFlowLocationOperation).AbsoluteLocation);
        }
        else
          flag1 = false;
      }
    }
    return flag1;
  }

  private bool AreTxTransformationsEqual(TxTransformation tran1, TxTransformation tran2)
  {
    TxTransformation txTransformation = TxTransformation.op_Multiply(tran1, tran2.Inverse);
    return txTransformation.Translation.X <= 0.001 && txTransformation.Translation.Y <= 0.001 && txTransformation.Translation.Z <= 0.001 && txTransformation.RotationRPY_XYZ.X <= 0.001 && txTransformation.RotationRPY_XYZ.Y <= 0.001 && txTransformation.RotationRPY_XYZ.Z <= 0.001;
  }

  public override void cleanup()
  {
    base.cleanup();
    this.m_simulationPlayer.OperationEndedForward -= new TxSimulationPlayer_OperationEndedForwardEventHandler(this.onOperationEndedForward);
    if (this.m_isRegisteredToOperationReachedEvent)
    {
      this.m_simulationPlayer.OperationReachedDestination -= new TxSimulationPlayer_OperationReachedDestinationEventHandler(this.m_simulationPlayer_OperationReachedDestination);
      this.m_isRegisteredToOperationReachedEvent = false;
    }
    this.UnRegisterToRoboticOlpEvents();
    this.m_isHandledFirstLocationReached = false;
  }

  private void onOperationEndedForward(
    object sender,
    TxSimulationPlayer_OperationEndedForwardEventArgs args)
  {
    ITxOperation operation = args.Operation;
    if (!(operation is ITxLocationOperation))
      return;
    bool flag = true;
    if (this.m_isHandledFirstLocationReached && operation == this.m_from)
      flag = false;
    if (!flag)
      return;
    this.handleLocationOperationReached(operation as ITxLocationOperation);
    if (operation != this.m_from)
      return;
    this.m_isHandledFirstLocationReached = true;
  }

  private void m_simulationPlayer_OperationReachedDestination(
    object sender,
    TxSimulationPlayer_OperationReachedDestinationEventArgs args)
  {
    if (!this.m_isHandledFirstLocationReached)
    {
      if (!(args.Operation is ITxLocationOperation) || args.Operation != this.m_from)
        return;
      this.handleLocationOperationReached(args.Operation as ITxLocationOperation);
      this.m_simulationPlayer.OperationReachedDestination -= new TxSimulationPlayer_OperationReachedDestinationEventHandler(this.m_simulationPlayer_OperationReachedDestination);
      this.m_isRegisteredToOperationReachedEvent = false;
      this.m_isHandledFirstLocationReached = true;
    }
    else
    {
      this.m_simulationPlayer.OperationReachedDestination -= new TxSimulationPlayer_OperationReachedDestinationEventHandler(this.m_simulationPlayer_OperationReachedDestination);
      this.m_isRegisteredToOperationReachedEvent = false;
    }
  }

  private void TxOlpRoboticSimulationEvents_SimEvent(TxOlpCTREventInfo simEvent)
  {
    if (!this.m_isHandledFirstLocationReached)
    {
      if (simEvent == null || this.m_from == null || !this.IsMotionToLocationFinished(simEvent, this.m_from))
        return;
      this.handleLocationOperationReached(this.m_from);
      this.UnRegisterToRoboticOlpEvents();
      this.m_isHandledFirstLocationReached = true;
    }
    else
      this.UnRegisterToRoboticOlpEvents();
  }

  private bool IsMotionToLocationFinished(TxOlpCTREventInfo simEvent, ITxLocationOperation locOp)
  {
    bool locationFinished = false;
    TxOlpCTRInternalEvent? olpEventType = this.GetOlpEventType(simEvent);
    if (olpEventType.HasValue)
    {
      TxOlpCTRInternalEvent? nullable = olpEventType;
      TxOlpCTRInternalEvent ctrInternalEvent = (TxOlpCTRInternalEvent) 0;
      if (nullable.GetValueOrDefault() == ctrInternalEvent & nullable.HasValue && simEvent.Status == null && simEvent.EventObject1 is ITxLocationOperation eventObject1 && eventObject1 == locOp)
        locationFinished = true;
    }
    return locationFinished;
  }

  private TxOlpCTRInternalEvent? GetOlpEventType(TxOlpCTREventInfo simEvent)
  {
    TxOlpCTRInternalEvent? olpEventType = new TxOlpCTRInternalEvent?();
    try
    {
      TxOlpCTRInternalEvent result;
      if (Enum.TryParse<TxOlpCTRInternalEvent>(simEvent.EventName, out result))
        olpEventType = new TxOlpCTRInternalEvent?(result);
    }
    catch (Exception ex)
    {
    }
    return olpEventType;
  }

  private void RegisterToRoboticOlpEvents()
  {
    if (this.m_isRegisteredToRoboticOlpEvents)
      return;
    TxOlpRoboticSimulationEvents.SimEvent += new TxOlpRoboticSimulationEvents.SimEventHandler(this.TxOlpRoboticSimulationEvents_SimEvent);
    this.m_isRegisteredToRoboticOlpEvents = true;
  }

  private void UnRegisterToRoboticOlpEvents()
  {
    if (!this.m_isRegisteredToRoboticOlpEvents)
      return;
    TxOlpRoboticSimulationEvents.SimEvent -= new TxOlpRoboticSimulationEvents.SimEventHandler(this.TxOlpRoboticSimulationEvents_SimEvent);
    this.m_isRegisteredToRoboticOlpEvents = false;
  }

  private void handleLocationOperationReached(ITxLocationOperation locationOp)
  {
    ITxLocationOperation locOp = locationOp;
    this.m_lastLocationReached = locOp;
    this.m_timeAtLastLocationReached = this.m_simulationPlayer.CurrentTime;
    this.triggerlocationReachedEvent();
    this.onLocationReached(locOp);
    this.m_reachedAllLocations = locationOp == this.LastLocation;
  }

  protected virtual void onLocationReached(ITxLocationOperation locOp)
  {
  }

  private void appendOperationLocations(ITxOperation operation)
  {
    TxTypeFilter txTypeFilter1 = new TxTypeFilter(typeof (ITxLocationOperation));
    switch (operation)
    {
      case ITxContinuousOperation _:
        TxTypeFilter txTypeFilter2 = new TxTypeFilter(typeof (TxRoboticSeamOperation));
        txTypeFilter2.AddIncludedType(typeof (ITxLocationOperation));
        using (IEnumerator<ITxObject> enumerator = ((Collection<ITxObject>) ((ITxObjectCollection) (operation as ITxContinuousOperation)).GetDirectDescendants((ITxTypeFilter) txTypeFilter2)).GetEnumerator())
        {
          while (enumerator.MoveNext())
          {
            ITxObject current = enumerator.Current;
            if (current is TxRoboticSeamOperation)
              ((TxObjectList<ITxObject>) this.m_operationLocations).Append((TxObjectList<ITxObject>) (current as TxRoboticSeamOperation).GetDirectDescendants((ITxTypeFilter) txTypeFilter1));
            else
              ((Collection<ITxObject>) this.m_operationLocations).Add(current);
          }
          break;
        }
      case ITxCompoundOperation _:
        ((TxObjectList<ITxObject>) this.m_operationLocations).Append((TxObjectList<ITxObject>) ((ITxObjectCollection) (operation as ITxCompoundOperation)).GetDirectDescendants((ITxTypeFilter) txTypeFilter1));
        break;
      case ITxLocationOperation _:
        ((Collection<ITxObject>) this.m_operationLocations).Add((ITxObject) operation);
        break;
    }
  }

  public event CApSVOrderedLocationsSimulationHandler.locationReachedEventHandler locationReached;

  private void triggerlocationReachedEvent()
  {
    if (this.locationReached == null)
      return;
    this.locationReached((object) this, new EventArgs());
  }

  public delegate void locationReachedEventHandler(object sender, EventArgs args);
}
